<template>
  <canvas :id="canvasId" :width="Number(props.radius) * 2" :height="Number(props.radius) * 2">
    Your browser does not support the canvas element.
  </canvas>
</template>
<script>
  export default {
    name: 'BasicRing',
  };
</script>

<script setup>
  import {
    ref,
    watchEffect,
    watch,
    reactive,
    toRefs,
    defineProps,
    defineEmits,
    defineExpose,
    markRaw,
    computed,
    toRaw,
    onMounted,
  } from 'vue';
  import { isArray } from '@/utils/config.js';
  import { setIndex, getIndex } from './setIndex.js';
  import { getColor } from '@/utils/transformColor.js';
  const props = defineProps({
    // id
    id: {
      type: String,
      default: '',
    },
    // 圆环半径
    radius: {
      type: [Number, String],
      default: 80,
    },
    // 数值
    value: {
      type: [Number, String],
      default: 0,
    },
    // 最大值
    maxValue: {
      type: [Number, String],
      default: 100,
    },
    // 进度条宽度
    borderWidth: {
      type: [Number, String],
      default: 10,
    },
    // 进度条颜色
    color: {
      type: [String, Array],
      default: ['#fff', '#0dd7de'],
    },
    // 背景色
    background: {
      type: String,
      default: 'rgba(0,0,0,0.2)',
    },
    // 背景色
    innerBackground: {
      type: String,
      default: '',
    },
    innerLineWidth: {
      type: [Number, String],
      default: 0,
    },
    lineCap: {
      type: String,
      default: 'square', // square  round
    },
    // 主标题
    title: {
      type: String,
      default: '',
    },
    // 副标题
    subTitle: {
      type: String,
      default: '%',
    },
    // 主标题样式
    titleStyle: {
      type: Object,
      default: () => {},
    },
    // 副标题样式
    subTitleStyle: {
      type: Object,
      default: () => {},
    },
    // 保留小数点位数
    percent: {
      type: [Number, String],
      default: '',
    },
    // 数值格式化（percent存在时，数值的.00是否需要去除）
    format: {
      type: Boolean,
      default: false,
    },
    // 初始步长
    startStep: {
      type: [Number, String],
      default: 0,
    },
    // 数值跳动步长
    step: {
      type: [Number, String],
      default: 1,
    },
    animate: {
      type: Boolean,
      default: false,
    },
  });

  // 渐变色
  const drawColor = (ctx, color1, color2) => {
    let gradient = ctx.createLinearGradient(
      Number(props.radius),
      0,
      Number(props.radius),
      Number(props.radius) * 2
    );
    gradient.addColorStop(0, color1);
    gradient.addColorStop(1, color2);
    ctx.strokeStyle = gradient;
  };
  Number(props.maxValue);
  // 画圆:  Canvas对象：ctx  圆心坐标: (x, y)  半径: radius  起始角度: startAngle 结束角度: endAngle 是否逆时针旋转: false 代表顺时针旋转  画笔尺寸  是否闭合  画笔颜色  填充颜色
  const drawCircle = (
    ctx,
    x,
    y,
    radius,
    startAngle,
    endAngle,
    Boolean,
    size,
    closePath,
    strokeColor,
    fillColor
  ) => {
    ctx.beginPath(); //beginPath() 方法开始一条路径，或重置当前的路径。
    ctx.lineCap = Number(props.value) === Number(props.maxValue) ? '' : props.lineCap;
    ctx.lineWidth = size; //画笔粗细
    ctx.strokeStyle = strokeColor; //画笔颜色
    ctx.arc(x, y, radius, startAngle, endAngle, Boolean); //路径
    closePath && ctx.closePath(); //结束路径
    if (fillColor) {
      ctx.fillStyle = fillColor;
      ctx.fill();
    } else {
      if (isArray(strokeColor)) {
        drawColor(ctx, strokeColor[0], strokeColor[1]);
      }
      ctx.stroke(); //开始画
    }
  };

  let num = Number(props.startStep);
  let colorArr = [];

  // 普通形式
  const init = (ctx) => {
    draw(ctx);
    drawText(ctx);
    drawSubText(ctx);
  };

  let step = Number(props.step);

  //动画形式
  const animate = (ctx) => {
    window.requestAnimationFrame(() => {
      if (num <= Number(props.value)) {
        animate(ctx);
      }
    });
    draw(ctx, num);
    drawText(ctx);
    drawSubText(ctx);
    if (num < Number(props.value) && num + 1 > Number(props.value)) {
      num = Number(props.value);
    } else {
      num += step;
    }
  };

  // 绘制（底圆、内嵌圆、渐变圆）
  const draw = (ctx, num) => {
    ctx.clearRect(0, 0, Number(props.radius) * 2, Number(props.radius) * 2);
    drawCircle(
      ctx,
      Number(props.radius),
      Number(props.radius),
      Number(props.radius) - Number(props.borderWidth) / 2,
      0,
      2 * Math.PI,
      false,
      Number(props.borderWidth),
      true,
      props.background
    );
    if (Number(props.value)) {
      const currentValue = num || Number(props.value);
      const value = num ? -Math.PI / 2 + ((2 * num) / 100) * Math.PI : Math.PI / 2;
      if (currentValue <= Number(props.maxValue) / 2) {
        drawCircle(
          ctx,
          Number(props.radius),
          Number(props.radius),
          Number(props.radius) - Number(props.borderWidth) / 2,
          -Math.PI / 2,
          -Math.PI / 2 + ((2 * currentValue) / 100) * Math.PI,
          false,
          Number(props.borderWidth),
          false,
          [props.color[0], colorArr[num ? Number(props.maxValue) / 2 : Number(props.value)]]
        );
      } else {
        drawCircle(
          ctx,
          Number(props.radius),
          Number(props.radius),
          Number(props.radius) - Number(props.borderWidth) / 2,
          -Math.PI / 2,
          value,
          false,
          Number(props.borderWidth),
          false,
          [props.color[0], colorArr[Number(props.maxValue) / 2]]
        );
        drawCircle(
          ctx,
          Number(props.radius),
          Number(props.radius),
          Number(props.radius) - Number(props.borderWidth) / 2,
          -Math.PI / 2 + 1 * Math.PI,
          -Math.PI / 2 + ((2 * currentValue) / 100) * Math.PI,
          false,
          Number(props.borderWidth),
          false,
          [props.color[1], colorArr[Number(props.maxValue) / 2]]
        );
      }
    }
    if (props.innerLineWidth) {
      drawCircle(
        ctx,
        Number(props.radius),
        Number(props.radius),
        Number(props.radius) - Number(props.borderWidth) - Number(props.innerLineWidth) / 2,
        0,
        Math.PI * 2,
        false,
        Number(props.innerLineWidth),
        true,
        props.innerBackground
      );
    }
  };

  setIndex();

  const canvasId = ref();
  canvasId.value = props.id || 'myCanvas' + getIndex();
  onMounted(() => {
    let myCanvas = document.getElementById(canvasId.value); //获取画布节点
    let ctx = myCanvas.getContext('2d'); //采用2d格式，并获取对象
    colorArr = getColor(props.color[0], props.color[1], Number(props.maxValue));
    props.animate ? animate(ctx) : init(ctx);
  });

  // 绘制文字
  let textWidth1 = 0;
  let textWidth2 = 0;
  let textWidth3 = 0;

  const fontStyle = {
    fontSize: 24,
    fontWeight: 500,
    textBaseline: 'Alphabetic',
    color: '',
    textAlign: 'center',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    unit: '',
    ...props.titleStyle,
  };

  // 绘制标题文字
  const drawText = (ctx) => {
    ctx.save();
    ctx.font = `${fontStyle.fontWeight} ${fontStyle.fontSize}px ${fontStyle.fontFamily}`;
    ctx.fillStyle = fontStyle.color || '#000';
    ctx.textAlign = fontStyle.textAlign;
    ctx.textBaseline = fontStyle.textBaseline;
    let value = props.animate
      ? num.toFixed(Number(props.percent))
      : Number(props.value).toFixed(Number(props.percent));
    if (props.percent && props.format && value == props.value) {
      value = value / 1;
    }
    if (props.title) {
      textWidth1 = ctx.measureText(props.title)?.width || 0;
    } else {
      if (props.animate) {
        if (num <= Number(props.value)) {
          textWidth2 = ctx.measureText(value + fontStyle.unit)?.width || 0;
        }
      } else {
        textWidth2 = ctx.measureText(value + fontStyle.unit)?.width || 0;
      }
    }
    value += fontStyle.unit;
    let defaultLeft = props.animate
      ? Number(props.radius) - textWidth3 / 2
      : Number(props.radius) - textWidth3 / 2 - 5;
    if (props.title) {
      defaultLeft += 5;
    }
    ctx.fillText(
      props.title || value,
      fontStyle.left || (fontStyle.right && Number(props.radius) - fontStyle.right) || defaultLeft,
      fontStyle.top ||
        (fontStyle.bottom && Number(props.radius) * 2 - fontStyle.bottom) ||
        Number(props.radius) + subFontStyle.fontSize / 2 + 3
    );
    ctx.restore();
  };

  // 副标题样式表
  const subFontStyle = {
    fontSize: 12,
    fontWeight: 'normal',
    textBaseline: 'Alphabetic',
    color: '',
    textAlign: 'center',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    ...props.subTitleStyle,
  };

  // 绘制副标题文字
  const drawSubText = (ctx) => {
    if (props.subTitle) {
      ctx.font = `${subFontStyle.fontWeight} ${subFontStyle.fontSize}px ${subFontStyle.fontFamily}`;
      ctx.fillStyle = subFontStyle.color || '#000';
      ctx.textAlign = subFontStyle.textAlign;
      ctx.textBaseline = subFontStyle.textBaseline;
      textWidth3 = ctx.measureText(props.subTitle)?.width || 0;
      let width = textWidth1 / 2 || textWidth2 / 2;
      ctx.fillText(
        props.subTitle,
        subFontStyle.left ||
          (subFontStyle.right && Number(props.radius) - subFontStyle.right) ||
          Number(props.radius) + width,
        subFontStyle.top ||
          (subFontStyle.bottom && Number(props.radius) * 2 - subFontStyle.bottom) ||
          Number(props.radius) + subFontStyle.fontSize / 2 + 2
      );
    }
  };
</script>
